﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ExportListing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        List<string> _searchPatterns = new List<string>();

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {

        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            var dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.Description = "Select solution dialog";
            System.Windows.Forms.DialogResult result = dialog.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {

                string folderPath = dialog.SelectedPath;
                System.IO.DirectoryInfo dir = new DirectoryInfo(folderPath);

                // Получаем нужные файлы
                string[] extensions = TxtExtensions.Text.Split(',');
                foreach (var extension in extensions)
                {
                    _searchPatterns.Add("*." + extension.Trim());
                }

                List<FileInfo> allNeededFiles = new List<FileInfo>();

                // Рекурсивный поиск
                CrawlAllFiles(dir.FullName, allNeededFiles);

                const string titleHeader = "Please wait... Processing {0} of {1} files.";
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork+= (s, a) =>
                    {
                        // Экспорт файлов
                        string tmpFilePath = System.IO.Path.GetTempFileName();
                        int count = allNeededFiles.Count;
                        int counter = 0;
                        bool removeComments = false;
                        Dispatcher.Invoke(new ThreadStart(() =>
                            {
                                removeComments = RemoveCommentsCB.IsChecked.GetValueOrDefault();
                            }));

                        using (FileStream fs = new FileStream(tmpFilePath, FileMode.OpenOrCreate, FileAccess.Write))
                        using (StreamWriter outfile = new StreamWriter(fs, Encoding.Unicode))
                        {
                            foreach (var file in allNeededFiles)
                            {
                                counter++;

                                Dispatcher.BeginInvoke(new ThreadStart(() =>
                                    {
                                        Title = string.Format(titleHeader, counter, count);
                                    }));

                                string fileText = File.ReadAllText(file.FullName);

                                // Удаляем комменты, если надо
                                if (removeComments)
                                {
                                    //// Сначала 2 слеша //
                                    //Regex r = new Regex(@"//.+$", RegexOptions.Multiline);
                                    //fileText = r.Replace(fileText, "");

                                    //// Теперь /**/
                                    //// Тут ? ищет первое вхождение до завершающего символа
                                    //// http://stackoverflow.com/questions/2503413/regular-expression-to-stop-at-first-match
                                    //r = new Regex(@"/\*.+?\*/", RegexOptions.Singleline);
                                    //fileText = r.Replace(fileText, "");

                                    // Новый вариант
                                    // http://stackoverflow.com/questions/3524317/regex-to-strip-line-comments-from-c-sharp/3524689#3524689

                                    var blockComments = @"/\*(.*?)\*/";
                                    var lineComments = @"//(.*?)\r?\n";
                                    var strings = @"""((\\[^\n]|[^""\n])*)""";
                                    var verbatimStrings = @"@(""[^""]*"")+";

                                    fileText = Regex.Replace(fileText,
                                        blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
                                        me =>
                                        {
                                            if (me.Value.StartsWith("/*") || me.Value.StartsWith("//"))
                                                return me.Value.StartsWith("//") ? Environment.NewLine : "";
                                            // Keep the literal strings
                                            return me.Value;
                                        },
                                        RegexOptions.Singleline);
                                }

                                outfile.Write(fileText);
                            }

                            outfile.Close();
                        }

                        // Спрашиваем, куда сохранить
                        Dispatcher.BeginInvoke(new ThreadStart(() =>
                                {
                                    var saveDlg = new System.Windows.Forms.SaveFileDialog();
                                    if (saveDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                                    {
                                        string pathToSave = saveDlg.FileName;
                                        if (File.Exists(pathToSave))
                                        {
                                            File.Delete(pathToSave);
                                        }
                                        File.Move(tmpFilePath, pathToSave);
                                        
                                        // Открываем каталог с файлом
                                        string destDir = System.IO.Path.GetDirectoryName(pathToSave);
                                        Process.Start(destDir);
                                    }
                                }));
                    };

                bw.RunWorkerAsync();
            }

        }

        // Сбор файлов
        private void CrawlAllFiles(string folderPath, List<FileInfo> allNeededFiles)
        {
            System.IO.DirectoryInfo dir = new DirectoryInfo(folderPath);

            // Получаем нужные файлы в папке
            foreach (var pattern in _searchPatterns)
            {
                allNeededFiles.AddRange(dir.GetFiles(pattern));
            }

            // Если есть в директории поддиректории, то распространяем действие на них
            var folders = dir.GetDirectories();
            foreach (var directoryInfo in folders)
            {
                CrawlAllFiles(directoryInfo.FullName, allNeededFiles);
            }
        }
    }
}
